﻿using System;
using System.Text;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

namespace Voodoo.SharePoint
{

    /// <summary>
    /// Wrapper for generic Queue that includes locking controls for
    /// thread safe access to the queue, we cant inherit Queue because
    /// some of the base methods are not overridable, so we wrap it
    /// </summary>
    internal class LockingQueue<T>
    {

        private bool _QueueIsOpen = false;
        private object _LockProxy = new object();
        private Queue<T> _Queue;

        public LockingQueue()
        {
            _QueueIsOpen = true;
            _Queue = new Queue<T>();
        }
        public LockingQueue(int capacity)
        {
            _QueueIsOpen = true;
            _Queue = new Queue<T>(capacity);
        }
        public LockingQueue(IEnumerable<T> collection)
        {
            _QueueIsOpen = true;
            _Queue = new Queue<T>(collection);
        }

        ~LockingQueue()
        {
            Close();
        }

        public void Close()
        {
            lock (_LockProxy)
            {
                _QueueIsOpen = false;
                _Queue.Clear();
                Monitor.PulseAll(_LockProxy);
            }
        }

        public T Dequeue()
        {
            lock (_LockProxy)
            {
                while (_QueueIsOpen && (_Queue.Count == 0))
                {
                    if (!Monitor.Wait(_LockProxy, Timeout.Infinite))
                    {
                        throw new QueueException("Unknown queue exception");
                    }
                }
                if (_QueueIsOpen)
                {
                    return _Queue.Dequeue();
                }
                else
                {
                    throw new QueueClosedException("Queue has been deactivated");
                }
            }
        }

        public void Enqueue(T t)
        {
            lock (_LockProxy)
            {
                _Queue.Enqueue(t);
                Monitor.Pulse(_LockProxy);
            }
        }
    }

    #region exceptions
    public class QueueClosedException : System.ApplicationException
    {
        public QueueClosedException()
            : base()
        {
        }
        public QueueClosedException(string errorMessage)
            : base(errorMessage)
        {
        }
        public QueueClosedException(string errorMessage, Exception innerErr)
            : base(errorMessage, innerErr)
        {
        }
    }

    public class QueueException : System.ApplicationException
    {
        public QueueException()
            : base()
        {
        }
        public QueueException(string errorMessage)
            : base(errorMessage)
        {
        }
        public QueueException(string errorMessage, Exception innerErr)
            : base(errorMessage, innerErr)
        {
        }
    }
    #endregion
   
}
